package com.progenies.ecg.asm31.model.codeparts.lines;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import com.progenies.ecg.asm31.util.BytecodeInstructionsUtils;
import com.progenies.ecg.asm31.util.GenerationUtils;
import com.progenies.ecg.asm31.util.VariableRegister.Variable;
import com.progenies.ecg.model.MethodObject;


public class ReturnVariableValue extends ConfigurableLineCodePart
{

	private String name;

	ReturnVariableValue(String name) {
		this.setName(name);
	}


	@Override
	public void generateBytecode()
	{
		if(this.visitor==null )
			throw new IllegalStateException("LinePart has not been configurated, please use ClassGenerator");
		
		if(name==null)
			visitor.visitInsn(Opcodes.RETURN);
		else
		{
			Variable originVar=varRegister.getVariable(name);
			
			if(originVar.isLocal())
				visitor.visitVarInsn(originVar.getType().getOpcode(Opcodes.ILOAD), originVar.getIndex());
			else
			{
				if(!originVar.isStatic())
					BytecodeInstructionsUtils.insertLocalVariableIntoStack(visitor, varRegister, "this");
				
				visitor.visitFieldInsn(originVar.isStatic()?Opcodes.GETSTATIC:Opcodes.GETFIELD, GenerationUtils.getFieldOwner(originVar.getName(), this.parent), originVar.getName(), originVar.getType().getDescriptor());
			}
			
			//is conversion needed?
			//i'll get returnType from method
			Type returnType=null;
			if(!(parent instanceof MethodObject))
				throw new RuntimeException("Return variables not supported on constructors");
			else
			{
				MethodObject method=(MethodObject)parent;
				returnType=Type.getType(method.getReturnType());
			}
			
			//conversion ALWAYS if needed
			int conversionOpcode=GenerationUtils.getCastNeeded(originVar.getType(), returnType);
			if(conversionOpcode!=Opcodes.NOP)
				visitor.visitInsn(conversionOpcode);
			
			visitor.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
		}
		
	}
	
	@Override
	public boolean isReturnCodePart() {
		return true;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}
